# -*- mode: python; coding: utf-8; -*-
##--------------------------------------------------------------------------##
##
## Copyright (C) 1998-2003 Markus Oberhumer <markus@oberhumer.com>
## Copyright (C) 2003 Mt. Hood Playing Card Co.
## Copyright (C) 2005-2010 Skomoroh <skomoroh@users.sourceforge.net>
## Copyright (C) 2010-2013 Jeremy Austin-Bardo <tjaustinbardo@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.
##
##--------------------------------------------------------------------------##
__docformat__ = "restructuredtext en"

from .. import formlib as layout

LEFT, RIGHT = layout.LEFT, layout.RIGHT


class CanfieldLayout(layout.Layout):
    """
    static block:
      - foundations [N]. (horz SUIT * 2. max 10 cols)
      - rows [S foundation]. `_offset` if `playcards`. `ncols` wide.

    dynamic block: align [LEFT | RIGHT].
      - talon [NW | NE].
      - waste [E talon | W talon]. `wastecards` ignored.
      - reserves [S talon]. (vert) `_offset` if `holdcards`. `ncards` if
        `reserve_texts`.

    :CVariables:
        _offset: func
          .. dict('ycards': [play|hold]cards)
          Margin and offset is below piles.

        _halign: func
          .. (max(ncols, f_cols + int(_has_waste)) - cols) * HXS
          Center static piles horz.
    """
    _offset = lambda self, cards: {'ycards': cards}
    _halign = lambda self, max_rows, piles: (max_rows - piles) * self.HXS

    def create(self, rows, ncols=None, playcards=12, bases=None,
               reserves=1, holdcards=0, reserve_texts=False,
               texts=False, align=LEFT, **kw):
        """
        create(rows[, ncols=rows, playcards=12, bases=suits * decks,
               reserves=1, holdcards=0, reserve_texts=False,
               texts=False, align=LEFT]) -> None

        :Parameters:
          rows : int
            Num of `s.rows` to include.

          ncols : int
            Num of horz piles before starting new row. Default `ROWS`.

          playcards : int
            Num of possible cards as margin on each pile on `s.rows`. A value
            of 0 sets no offset and a value greater sets an offset. Default
            `12`.

          bases : tuple | list
            Value of each `suit` capabilty on `s.foundations`. Len is num of
            piles to include. Default `SUITS * DECKS`.

          reserves : int
            Num of `s.reserves` piles to include. Default `0`.

          holdcards : int
            Num of possible cards as margin on each pile on `s.reserves`. A
            value of 0 sets no offset and a value greater sets an offset.
            Default `0`.

          reserve_texts : bool
            Whether to include num cards text label for `s.reserves`. Default
            `False`.

          texts : bool
            Whether to include num cards text label for `s.talon` and possible
            `s.waste`. Default `False`.

          align : LEFT | RIGHT
            Dynamic placement of `s.talon`, possible `s.waste`, and possible
            `s.reserves`. `s.foundations` placement is opposite side. Default
            `LEFT`
        """
        l, s = self, self.s
        ncols = ncols or rows
        # Set foundation
        bases = bases if type(bases) in (list, tuple) else l.SUITS
        f_cols = min(10, (len(bases) / l.NDECKS) * min(2, l.NDECKS))
        # Set remain alignment
        max_cols = max(ncols, f_cols + int(l._has_waste))
        row_align = lambda piles: l._halign(max_cols, piles)
        # Allow sub class
        ix = max(l.size.width, l.XM)
        # Static align foundation N
        sx = (ix if align == RIGHT else ix + (1 + int(l._has_waste)) * l.XS)
        l._set_horz_foundations(x=sx, y=l.YM, ncols=f_cols, bases=bases)
        # Static align row beneath foundation
        sx = (ix  if align == RIGHT else ix + l.XS)
        l._set_rows(x=sx + row_align(ncols), y=l.size.height +l.TEX_HEIGHT,
                    rows=rows, ncols=ncols, **l._offset(playcards))
        # Dynamic align to `align` edge talon, waste
        dx = ix if align == LEFT else l.size.width - l.XS
        l._set_horz_talon(x=dx, y=l.YM, texts=texts, align=align, anchor='s',
                          wastecards=0)
        anchor = 'e' if align == LEFT else 'w'
        s['talon'].set_rounds(anchor='sss' if l._has_waste else anchor)
        # Dynamic align to `align` edge reserve
        dy = l.TEXT_HEIGHT * 2 if texts else 0
        l._set_vert_reserves(x=s['talon'].x, y=s['talon'].y + l.YS + dy,
                             reserves=reserves, reserve_texts=reserve_texts,
                             anchor=anchor, **l._offset(holdcards))


class InternmentLayout(layout.Layout):
    """
    static block:
      - foundations [N]. (horz SUIT * 2. max 10 cols)
      - rows [S foundation]. `_offset` if `playcards`. `ncols` wide.

    dynamic block: align [LEFT | RIGHT].
      - talon [NW | NE].
      - waste [E talon | W talon]. `wastecards` ignored.
      - xwastes [S talon]. (vert). `ncards` if `xwaste_texts`.
      - reserves [NE | NW]. (vert). `_offset` if `holdcards`. `ncards` if
        `reserve_texts`).

    :CVariables:
        _offset: func
          .. dict('ycards': [play|hold]cards)
          Margin and offset is below piles.

        _halign: func
          .. (max(ncols, f_cols + int(_has_waste)) - cols) * HXS
          Center static piles horz.
    """

    _offset = lambda self, cards: {'ycards': cards}
    _halign = lambda self, max_rows, piles: (max_rows - piles) * self.HXS

    def create(self, rows, ncols=None, playcards=12, bases=None,
               reserves=6, holdcards=0, reserve_texts=False,
               texts=False, align=LEFT, xwastes=3, xwastestext=True, **kw):
        """
        create(rows[, ncols=rows, playcards=12, bases=suits * decks,
          reserves=1, holdcards=0, reserve_texts=False, texts=False,
          align=LEFT, xwastes=3, xwaste_texts=True]) -> None

        :Parameters:
          rows : int
            Num of `s.rows` to include.

          ncols : int
            Num of horz piles before starting new row. Default `ROWS`.

          playcards : int
            Num of possible cards as margin on each pile on `s.rows`. A value
            of 0 sets no offset and a value greater sets an offset. Default
            `12`.

          bases : tuple | list
            Value of each `suit` capabilty on `s.foundations`. Len is num of
            piles to include. Default `SUITS * DECKS`.

          reserves : int
            Num of `s.reserves` piles to include. Default `6`.

          holdcards : int
            Num of possible cards as margin on each pile on `s.reserves`. A
            value of 0 sets no offset and a value greater sets an offset.
            Default `0`.

          reserve_texts : bool
            Whether to include num cards text label for `s.reserves`. Default
            `False`.

          xwastes : int
            Num of `s.xwastes` piles to include. Default `3`.

          xwaste_texts : bool
            Whether to include num cards text label for `s.xwastes`. Default
            `True`.

          texts : bool
            Whether to include num cards text label for `s.talon` and possible
            `s.waste`. Default `False`.

          align : LEFT | RIGHT
            Dynamic placement of `s.talon`, possible `s.waste`, and possible
            `s.reserves`. `s.foundations` placement is opposite side. Default
            `LEFT`
        """
        l, s = self, self.s
        ncols = ncols or rows
        # Set foundation
        bases = bases if type(bases) in (list, tuple) else l.SUITS
        f_cols = min(10, (len(bases) / l.NDECKS) * min(2, l.NDECKS))
        # Set remain alignment
        max_cols = max(ncols, f_cols + 1 + int(l._has_waste))
        row_align = lambda piles: l._halign(max_cols, piles)
        # Allow sub class
        ix = max(l.size.width, l.XM)
        # Static align foundation N
        sx = (ix if align == RIGHT else ix + (1 + int(l._has_waste)) * l.XS)
        l._set_horz_foundations(x=sx + row_align(f_cols), y=l.YM,
                                ncols=f_cols, bases=bases)
        # Static align row beneath foundation
        sx = (ix  if align == RIGHT else ix + l.XS)
        l._set_rows(x=sx + row_align(rows), y=l.size.height, rows=rows,
                    ncols=ncols, **l._offset(playcards))
        # Dynamic align to `align` edge talon, waste
        dx = ix if align == LEFT else l.size.width + l.XM
        l._set_horz_talon(x=dx, y=l.YM, texts=texts, align=align,
                          anchor='s', wastecards=0)
        anchor = 'e' if align == LEFT else 'w'
        s['talon'].set_rounds(anchor='sss' if l._has_waste else anchor)
        # Dynamic align to `align` edge xwastes
        dy = l.TEXT_HEIGHT * 2 if texts else 0
        for x, y in l.row_block_iter(x=s['talon'].x, y=s['talon'].y + l.YS + dy,
                                     npiles=xwastes, nrows=xwastes):
            s['xwastes'].append(self._create_stack(x, y))
            if xwastestext:
                s['xwastes'][-1].set_ncards(anchor=anchor)
        # Dynamic align opposite edge vert reserve
        sx = (ix if align == RIGHT else l.size.width + l.XM)
        l._set_vert_reserves(x=sx, y=l.YM, reserves=reserves,
                             reserve_texts=reserve_texts, anchor='w',
                             **l._offset(holdcards))

    def defaultAll(self):
        """
        defaultAll() -> None

        Set default for texts, groups, and regions.
        """
        game = self.game
        xwastes = self.s['xwastes']
        if game.s['xwastes'] and xwastes:
            if xwastes.ncards:
                self.set_ncards_text(game.s['xwastes'], **xwastes.ncards)
        super(InternmentLayout, self).defaultAll(self)


class DoorwayLayout(layout.Layout):
    """
    static block (top):
        - foundations. (horz SUIT * 2. max of 10 cols)
        - reserves. (1. YOFFSET if holdcards. ncards if reserve_texts.)
          rows (YOFFSET if playcards).
          reserves. (1. YOFFSET if holdcards. ncards if reserve_texts.)

    dynamic block (top): align LEFT or RIGHT side. default LEFT.
        - talon (corner). waste (if Game._waste_. wastecards ignored).

    :cvar func _offset: dict('ycards': value)
    """

    _offset = lambda self, cards: {'ycards': cards}
    _halign = lambda self, max_rows, piles: (max_rows - piles) * self.HXS

    def create(self, rows, ncols=None, playcards=12, bases=None,
               holdcards=0, reserves=2, reserve_texts=False,
               align=LEFT, texts=True, **kw):
        l, s = self, self.s
        ncols = ncols or rows
        t_size = 1 + int(l._has_waste)
        # set foundation base caps
        bases = bases if type(bases) in (list, tuple) else l.SUITS
        f_cols = min(10, (len(bases) / l.NDECKS) * min(2, l.NDECKS))
        # set max piles for centering groups
        max_cols = max(ncols + reserves, f_cols + t_size)
        row_align = lambda piles: self._halign(max_cols, piles)
        # allow sub class usage
        ix = max(l.size.width, l.XM)
        # adjust for talon
        sx = l.XM + (ix if align == RIGHT else ix + t_size * l.XS)
        l._set_horz_foundations(x=sx, y=l.YM, ncols=f_cols, bases=bases)
        l._set_rows(x=ix + row_align(ncols), y=l.size.height, rows=rows,
                    ncols=ncols, **l._offset(playcards))
        # set custom reserve either side rows
        reserves /= 2
        l.set_vert_reserve(x=l.s['rows'][0].x - l.XS * reserves - l.XM,
                           reserves=reserves, reserve_texts=reserve_texts,
                           **l._offset(holdcards))
        l.set_vert_reserve(x=l.s['rows'][ncols - 1].x + l.XS + l.XM,
                           reserves=reserves, reserve_texts=reserve_texts,
                           **l._offset(holdcards))
        # adjust for talon
        dx = ix if align == LEFT else l.size.width - l.XS
        l._set_horz_talon(x=dx, y=l.YM, texts=texts, align=align, anchor='n',
                          wastecards=0)
        anchor = 'e' if align == LEFT else 'w'
        s['talon'].set_rounds(anchor='nnn' if l._has_waste else anchor)